Skip to content

DRAFT: do not set LIBRARY_PATH for LLVM and adapt compiler config to insert paths instead - #4089

Closed
Thyre wants to merge 4 commits into
easybuilders:developfrom
Thyre:20260306092023_new_pr_llvm
Closed

DRAFT: do not set LIBRARY_PATH for LLVM and adapt compiler config to insert paths instead#4089
Thyre wants to merge 4 commits into
easybuilders:developfrom
Thyre:20260306092023_new_pr_llvm

Conversation

@Thyre

@Thyre Thyre commented Mar 6, 2026

Copy link
Copy Markdown
Collaborator

(created using eb --new-pr)

LLVM is a major part of our toolchains, especially since we started to use a single LLVM installation including all bells and whistles. However, this can lead to incorrect libraries being picked up when multiple LLVM-based applications are loaded.

In the case of ROCm-LLVM and LLVM, I encountered issues when e.g. Mesa & ROCm-LLVM are loaded. Mesa has a dependency on LLVM, hence polluting LIBRARY_PATH with its libraries. When we then try to build an application with ROCm-LLVM, we potentially pick up the incorrect OpenMP libraries (and other LLVM ones).

jreuter@Linux  ~  ml rocm-compilers HIP
jreuter@Linux  ~  amdclang -fopenmp --offload-arch=gfx1201 test.c && ldd a.out | grep libomptarget
        libomptarget.so.20.1 => /data/EasyBuild-develop/software/LLVM/20.1.8-GCCcore-14.3.0/lib/x86_64-unknown-linux-gnu/libomptarget.so.20.1 (0x00007f7f786f5000)
jreuter@Linux  ~  unset LIBRARY_PATH
jreuter@Linux  ~  amdclang -fopenmp --offload-arch=gfx1201 test.c && ldd a.out | grep libomptarget
        libomptarget.so.22.0git => /data/EasyBuild-develop/software/ROCm-LLVM/22.0.0-GCCcore-14.3.0-ROCm-7.2.0/lib/x86_64-unknown-linux-gnu/libomptarget.so.22.0git (0x00007fb000000000)

For Mesa, this could be solved easily: Move LLVM to being included statically, hence moving LLVM to a build dependency. However, a long time solution would be desirable.

This PR tries to achieve this by removing LIBRARY_PATH from LLVM altogether, as suggested by @ocaisa. We do a similar approach with GCC.
This however needs very thorough testing. I'm very confident that LLVM knows where to find its stuff, but less confident about applications using just some parts of LLVM. They should rely on what llvm-config or LLVM's CMake scripts provide, but you never know.

Unfortunately, only adapting the compiler configuration is insufficient. LLVM rpaths LIBRARY_PATH before any arguments passed by the user (including config files), so we cannot reliably influence which libraries are picked up at the end.

@Thyre
Thyre marked this pull request as draft March 6, 2026 08:20
@Thyre Thyre changed the title do not set LIBRARY_PATH for LLVM and adapt compiler config to insert paths instead DRAFT: do not set LIBRARY_PATH for LLVM and adapt compiler config to insert paths instead Mar 6, 2026
@Thyre

Thyre commented Mar 9, 2026

Copy link
Copy Markdown
Collaborator Author

Test report by @Thyre

Overview of tested easyconfigs (in order)

Build succeeded for 0 out of 1 (total: 30 mins 29 secs) (1 easyconfigs in total)
Linux - Linux Arch Linux UNKNOWN, x86_64, AMD Ryzen 7 7800X3D 8-Core Processor (zen4), 1 x AMD Navi 48 [Radeon RX 9070/9070 XT/9070 GRE] (device id: 0x7550, gfx: gfx1201, driver: Linuxversion6.19.6-arch1-1(linux@archlinux)(gcc(GCC)15.2.120260209,GNUld(GNUBinutils)2.46)#1SMPPREEMPT_DYNAMICWed,04Mar202618:25:08+0000), 1 x AMD Raphael (device id: 0x164e, gfx: gfx1036, driver: Linuxversion6.19.6-arch1-1(linux@archlinux)(gcc(GCC)15.2.120260209,GNUld(GNUBinutils)2.46)#1SMPPREEMPT_DYNAMICWed,04Mar202618:25:08+0000), Python 3.14.3
See https://gist.github.com/Thyre/26b5f8df7d1c1de4129e1eb40636967f for a full test report.

Comment thread easybuild/easyblocks/l/llvm.py Outdated
Signed-off-by: Jan André Reuter <j.reuter@fz-juelich.de>
@Thyre
Thyre force-pushed the 20260306092023_new_pr_llvm branch from c44fcef to 3e778c8 Compare March 9, 2026 11:37
@Thyre

Thyre commented Mar 9, 2026

Copy link
Copy Markdown
Collaborator Author

Test report by @Thyre

Overview of tested easyconfigs (in order)

Build succeeded for 0 out of 1 (total: 2 hours 9 mins 24 secs) (1 easyconfigs in total)
Linux - Linux Arch Linux UNKNOWN, x86_64, AMD Ryzen 7 7800X3D 8-Core Processor (zen4), 1 x AMD Navi 48 [Radeon RX 9070/9070 XT/9070 GRE] (device id: 0x7550, gfx: gfx1201, driver: Linuxversion6.19.6-arch1-1(linux@archlinux)(gcc(GCC)15.2.120260209,GNUld(GNUBinutils)2.46)#1SMPPREEMPT_DYNAMICWed,04Mar202618:25:08+0000), 1 x AMD Raphael (device id: 0x164e, gfx: gfx1036, driver: Linuxversion6.19.6-arch1-1(linux@archlinux)(gcc(GCC)15.2.120260209,GNUld(GNUBinutils)2.46)#1SMPPREEMPT_DYNAMICWed,04Mar202618:25:08+0000), Python 3.14.3
See https://gist.github.com/Thyre/885e6b73a50a2cc84019e94f4d3d7bd9 for a full test report.

@Thyre

Thyre commented Mar 9, 2026

Copy link
Copy Markdown
Collaborator Author

The multi-stage build failed because the compiler config file now picks up Stage 2 during the Stage 3 build, hence causing flang to link to the wrong libclang-cpp.so and libLLVM.so.

So we really need to only add the compiler paths for the final installation.

@Thyre Thyre added the change label Mar 11, 2026
Signed-off-by: Jan André Reuter <j.reuter@fz-juelich.de>
@Thyre

Thyre commented Mar 11, 2026

Copy link
Copy Markdown
Collaborator Author

Test report by @Thyre

Overview of tested easyconfigs (in order)

Build succeeded for 0 out of 1 (total: 6 hours 29 mins 39 secs) (1 easyconfigs in total)
jrc0850.jureca - Linux Rocky Linux 9.7 (Blue Onyx), x86_64, AMD EPYC 7443 24-Core Processor (zen3), 8 x AMD AMD INSTINCT MI250 (MCM) OAM AC MBA (device id: 0x740c, gfx: gfx90a, driver: 6.16.6), Python 3.9.25
See https://gist.github.com/Thyre/61e041f69c022aff98983611eeb4a5c7 for a full test report.

Signed-off-by: Jan André Reuter <j.reuter@fz-juelich.de>
@Thyre

Thyre commented Mar 11, 2026

Copy link
Copy Markdown
Collaborator Author

lld really did not like -Wl,-rpath= in the host offload tests. Trying a different approach. Test running...

@Thyre

Thyre commented Mar 11, 2026

Copy link
Copy Markdown
Collaborator Author

Test report by @Thyre

Overview of tested easyconfigs (in order)

Build succeeded for 0 out of 1 (total: 6 hours 29 mins 0 secs) (1 easyconfigs in total)
jrc0850.jureca - Linux Rocky Linux 9.7 (Blue Onyx), x86_64, AMD EPYC 7443 24-Core Processor (zen3), 8 x AMD AMD INSTINCT MI250 (MCM) OAM AC MBA (device id: 0x740c, gfx: gfx90a, driver: 6.16.6), Python 3.9.25
See https://gist.github.com/Thyre/21bedd618f08d2653e02174dcd861fc1 for a full test report.

@Thyre

Thyre commented Mar 12, 2026

Copy link
Copy Markdown
Collaborator Author

Still hitting the same failure:

# .---command stderr------------
# | clang: error: unknown argument '--rpath'; did you mean '-rpath'?
# | /dev/shm/reuter1/easybuild/build/LLVM/20.1.8/GCCcore-14.3.0/llvm.obj.3/bin/clang-linker-wrapper: error: 'clang' failed
# | clang++: error: linker command failed with exit code 1 (use -v to see invocation)
# `-----------------------------
# error: command failed with exit status: 1

Wondering if I hit some Clang driver bug here. We certainly only specify -Wl,-rpath in our config file.

/dev/shm/reuter1/easybuild/build/LLVM/20.1.8/GCCcore-14.3.0/llvm.obj.3/./bin/clang++ -fopenmp -I /dev/shm/reuter1/easybuild/build/LLVM/20.1.8/GCCcore-14.3.0/llvm-project-20.1.8.src/offload/test -I /dev/shm/reuter1/easybuild/build/LLVM/20.1.8/GCCcore-14.3.0/llvm.obj.3/./lib/../projects/openmp/runtime/src -L /dev/shm/reuter1/easybuild/build/LLVM/20.1.8/GCCcore-14.3.0/llvm.obj.3/runtimes/runtimes-bins/offload -L /dev/shm/reuter1/easybuild/build/LLVM/20.1.8/GCCcore-14.3.0/llvm.obj.3/./lib -L /dev/shm/reuter1/easybuild/build/LLVM/20.1.8/GCCcore-14.3.0/llvm.obj.3/runtimes/runtimes-bins/openmp/runtime/src -nogpulib -Wl,-rpath,/dev/shm/reuter1/easybuild/build/LLVM/20.1.8/GCCcore-14.3.0/llvm.obj.3/runtimes/runtimes-bins/offload -Wl,-rpath,/dev/shm/reuter1/easybuild/build/LLVM/20.1.8/GCCcore-14.3.0/llvm.obj.3/./lib -foffload-lto -fopenmp-targets=x86_64-unknown-linux-gnu /dev/shm/reuter1/easybuild/build/LLVM/20.1.8/GCCcore-14.3.0/llvm-project-20.1.8.src/offload/test/offloading/assert.cpp -o /dev/shm/reuter1/easybuild/build/LLVM/20.1.8/GCCcore-14.3.0/llvm.obj.3/runtimes/runtimes-bins/offload/test/x86_64-unknown-linux-gnu-LTO/offloading/Output/assert.cpp.tmp /dev/shm/reuter1/easybuild/build/LLVM/20.1.8/GCCcore-14.3.0/llvm.obj.3/./lib/libomptarget.devicertl.a

# Add flags to make sure LLVM picks up its own directories correctly.
# This ensures that LLVM finds it own stuff, even when LIBRARY_PATH is not set.
opts.append(f'-L{installdir}/lib')
opts.append(f'-Wl,-rpath={installdir}/lib')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we are using rpath wrappers this is redundant

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main point here is that people might still use LLVM without rpath wrappers (or a buildenv module), but we still want to make sure we're picking up the correct libraries.

runtime_libdir = self.get_runtime_lib_path(installdir, fail_ok=True)
if os.path.exists(runtime_libdir):
opts.append(f'-L{installdir}/{runtime_libdir}')
opts.append(f'-Wl,-rpath,{installdir}/{runtime_libdir}')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, even if we are not setting LIBRARY_PATH we should still have LD_LIBRARY_PATH when not using rpathing so these are probably not needed

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about EESSI, where LD_LIBRARY_PATH is filtered?
I also want to make sure that we do not accidentally pick up a wrong libomp.so, e.g. from ROCm-LLVM when LLVM is loaded.

@Crivella

Crivella commented Mar 26, 2026

Copy link
Copy Markdown
Contributor

I'm wondering if this could be more easily solved by appending the LIBRARY_PATH for CORE compilers instead of prepending it so that even if the load order is something like

  • ROCm-LLVM
  • MESA
    • LLVM

we end up with the ROCm-LLVM libraries before the LLVM ones

OFC this works if we have only 1 level of core compilers.
(EDIT: which if i think more about it might already be the case with ROCm-LLVM -> LLVM -> GCCcore)
I guess this could be an LMOD feature to give a priority to the prepend path or to have a first-path that ensures that path is always first

@Crivella

Copy link
Copy Markdown
Contributor

I guess an LMOD alternative could also be something like

  • CORE compiler loaded first sets LIBRARY_PATH and another environment variable (eg EB_CORE_COMPILER)
  • CORE compilers loaded should always check for that flag environment variable and only add to LIBRARY_PATH if it is not set

@boegel boegel added this to the 5.x milestone Jun 16, 2026
@boegel

boegel commented Jun 16, 2026

Copy link
Copy Markdown
Member

Didn't look into this in detail, but in some places we may assume that $LIBRARY_PATH includes all expected paths, see for example:

@Thyre

Thyre commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator Author

Didn't look into this in detail, but in some places we may assume that $LIBRARY_PATH includes all expected paths, see for example:

Agreed that we need to be careful here, and ensure that the correct rpath is still set.
In this PR, I try to ensure that by still setting -Wl,-rpath in the compiler config file.

But, given that I haven't managed to get a single successful build due to the LLVM tests, I'm not sure if this is the right approach going forward...

easybuilders/easybuild-easyconfigs#26267 will solve the easiest case to run into mixing LLVM versions, Mesa. For now, I consider this to be the better approach.

@Thyre

Thyre commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator Author

Given the failure we saw with GCC 14.2.0 because of a missing LIBRARY_PATH and the complexities of getting this to work with the LLVM tests, I'm skeptical that this is the right approach.

Instead, we should try to explicitly link LLVM as a static library whenever possible. That gets rid of the hard dependency, removing the chance that libraries clash.

With that, I'll go ahead and close the PR. If this comes up again, we can use this as a starting point, if necessary.

@Thyre Thyre closed this Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants